package org.lex.notepad.ui.preferences;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Locale;

import javax.swing.JCheckBox;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;


import org.lex.app.prefs.ResourceMap;
import org.lex.notepad.Notepad;
import org.lex.notepad.util.CK;
import org.lex.notepad.util.CharsetUtils;
import org.lex.string.StringUtils;
import org.lex.swing.prefs.CategoryAdapter;
import org.lex.swing.widgets.CharsetSelectorComboBox;
import org.lex.swing.widgets.ColorSelectorButton;
import org.lex.swing.widgets.FontSelectorButton;
import org.lex.swing.widgets.JLabelSeparator;
import org.lex.utils.Codec;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class EditorCategory extends CategoryAdapter {
	private Logger log = LoggerFactory.getLogger(EditorCategory.class);

	private JCheckBox wrapLineCheckBox = null;
	private JCheckBox wrapWordCheckBox = null;
	private JLabel encodingLabel = null;
	private JLabel fontLabel = null;
	private FontSelectorButton fontButton = null;
	private JLabel backgroundLabel = null;
	private ColorSelectorButton backgroundButton = null;
	private JLabel foregroundLabel = null;
	private ColorSelectorButton foregroundButton = null;
	private JLabelSeparator colorsSeparator = null;
	private JPanel gluePane = null;
	private JLabel tabSizeLabel = null;
	private JTextField tabSizeTextField = null;
	private JLabel selectionLabel = null;
	private ColorSelectorButton selectionColorButton = null;
	private CharsetSelectorComboBox charsetComboBox = null;

	@Override
	public String getTitle() {
		return "Notepad.Editor";
	}

	@Override
	public void loadConfiguration() {
		ResourceMap cfg = Notepad.getApplication().getContext().getResourceManager().getResourceMap();
		// charset
		Charset cs = null;
		String charsetName = cfg.getString(CK.EDITOR_ENCODING);
		if (false == StringUtils.isNullOrTrimEmpty(charsetName)) {
			try {
				cs = Charset.forName(cfg.getString(CK.EDITOR_ENCODING));
			} catch (UnsupportedCharsetException e) {
				log.warn("charset [" + charsetName + "] not found, restore system default", e);
			}
		}
		if (null == cs) {
			cs = Charset.defaultCharset();
		}
		log.debug(CK.EDITOR_ENCODING + "=" + cs);
		getCharsetComboBox().setSelectedCharset(cs);

		getTabSizeTextField().setText(cfg.getString(CK.EDITOR_TAB_SIZE));
		getWrapWordCheckBox().setSelected(cfg.getBoolean(CK.EDITOR_WRAP_WORD));
		boolean wrapLine = cfg.getBoolean(CK.EDITOR_WRAP_LINE);
		getWrapWordCheckBox().setEnabled(wrapLine);
		getWrapLineCheckBox().setSelected(wrapLine);
		// load font
		Font font = Codec.decodeFont(cfg.getString(CK.EDITOR_FONT));
		this.getFontButton().setSelectedFont(font);
		// load colors
		String fore = cfg.getString(CK.EDITOR_TEXT_COLOR);
		if (null != fore && false == fore.isEmpty())
			this.getForegroundButton().setSelectedColor(Color.decode(fore));
		String back = cfg.getString(CK.EDITOR_BACKGROUND);
		if (null != back && false == back.isEmpty())
			this.getBackgroundButton().setSelectedColor(Color.decode(back));
		String selection = cfg.getString(CK.EDITOR_SELECTION_COLOR);
		if (null != selection && false == selection.isEmpty())
			this.getSelectionColorButton().setSelectedColor(Color.decode(selection));
		this.fireContentChanged(false);
	}

	@Override
	public void saveConfiguration() {
		ResourceMap cfg = Notepad.getApplication().getContext().getResourceManager().getResourceMap();
		cfg.putString(CK.EDITOR_ENCODING, getCharsetComboBox().getSelectedCharset().name());
		cfg.putString(CK.EDITOR_TAB_SIZE, getTabSizeTextField().getText().trim());
		cfg.putProperty(CK.EDITOR_WRAP_LINE, getWrapLineCheckBox().isSelected());
		cfg.putProperty(CK.EDITOR_WRAP_WORD, getWrapWordCheckBox().isSelected());
		// save font
		cfg.putString(CK.EDITOR_FONT, Codec.encodeFont(getFontButton().getSelectedFont()));
		// save colors
		Color fore = this.getForegroundButton().getSelectedColor();
		Color back = this.getBackgroundButton().getSelectedColor();
		Color selection = this.getSelectionColorButton().getSelectedColor();
		cfg.putString(CK.EDITOR_TEXT_COLOR, Codec.encodeColor(fore));
		cfg.putString(CK.EDITOR_BACKGROUND, Codec.encodeColor(back));
		cfg.putString(CK.EDITOR_SELECTION_COLOR, Codec.encodeColor(selection));
	}

	public EditorCategory() {
		super();
		this.initialize();
	}

	private void initialize() {
		GridBagConstraints gridBagConstraints14 = new GridBagConstraints();
		gridBagConstraints14.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints14.gridy = 2;
		gridBagConstraints14.weightx = 0.0;
		gridBagConstraints14.insets = new Insets(0, 5, 5, 5);
		gridBagConstraints14.gridx = 1;
		GridBagConstraints gridBagConstraints23 = new GridBagConstraints();
		gridBagConstraints23.gridx = 1;
		gridBagConstraints23.anchor = GridBagConstraints.WEST;
		gridBagConstraints23.insets = new Insets(0, 5, 5, 5);
		gridBagConstraints23.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints23.gridy = 7;
		GridBagConstraints gridBagConstraints13 = new GridBagConstraints();
		gridBagConstraints13.gridx = 0;
		gridBagConstraints13.anchor = GridBagConstraints.WEST;
		gridBagConstraints13.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints13.gridy = 7;
		selectionLabel = new JLabel();
		selectionLabel.setText("Selection");
		GridBagConstraints gridBagConstraints22 = new GridBagConstraints();
		gridBagConstraints22.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints22.gridy = 1;
		gridBagConstraints22.weightx = 0.0;
		gridBagConstraints22.insets = new Insets(0, 5, 5, 5);
		gridBagConstraints22.gridx = 1;
		GridBagConstraints gridBagConstraints12 = new GridBagConstraints();
		gridBagConstraints12.gridx = 0;
		gridBagConstraints12.anchor = GridBagConstraints.WEST;
		gridBagConstraints12.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints12.gridy = 1;
		tabSizeLabel = new JLabel();
		tabSizeLabel.setText("Tab size");
		GridBagConstraints gridBagConstraints = new GridBagConstraints();
		gridBagConstraints.gridx = 0;
		gridBagConstraints.fill = GridBagConstraints.BOTH;
		gridBagConstraints.weightx = 10.0;
		gridBagConstraints.weighty = 10.0;
		gridBagConstraints.gridwidth = 3;
		gridBagConstraints.gridy = 8;
		GridBagConstraints gridBagConstraints61 = new GridBagConstraints();
		gridBagConstraints61.gridx = 0;
		gridBagConstraints61.gridwidth = 3;
		gridBagConstraints61.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints61.weightx = 10.0;
		gridBagConstraints61.insets = new Insets(11, 0, 3, 0);
		gridBagConstraints61.gridy = 4;
		colorsSeparator = new JLabelSeparator("Colors");
		GridBagConstraints gridBagConstraints41 = new GridBagConstraints();
		gridBagConstraints41.gridx = 1;
		gridBagConstraints41.anchor = GridBagConstraints.WEST;
		gridBagConstraints41.insets = new Insets(0, 5, 5, 5);
		gridBagConstraints41.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints41.gridy = 6;
		GridBagConstraints gridBagConstraints3 = new GridBagConstraints();
		gridBagConstraints3.gridx = 0;
		gridBagConstraints3.anchor = GridBagConstraints.WEST;
		gridBagConstraints3.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints3.gridy = 6;
		foregroundLabel = new JLabel();
		foregroundLabel.setText("Text");
		GridBagConstraints gridBagConstraints21 = new GridBagConstraints();
		gridBagConstraints21.gridx = 1;
		gridBagConstraints21.anchor = GridBagConstraints.WEST;
		gridBagConstraints21.insets = new Insets(0, 5, 5, 5);
		gridBagConstraints21.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints21.gridy = 5;
		GridBagConstraints gridBagConstraints11 = new GridBagConstraints();
		gridBagConstraints11.gridx = 0;
		gridBagConstraints11.anchor = GridBagConstraints.WEST;
		gridBagConstraints11.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints11.gridy = 5;
		backgroundLabel = new JLabel();
		backgroundLabel.setText("Background");
		GridBagConstraints gridBagConstraints2 = new GridBagConstraints();
		gridBagConstraints2.gridx = 1;
		gridBagConstraints2.anchor = GridBagConstraints.WEST;
		gridBagConstraints2.insets = new Insets(3, 5, 5, 5);
		gridBagConstraints2.fill = GridBagConstraints.NONE;
		gridBagConstraints2.gridwidth = 2;
		gridBagConstraints2.gridy = 3;
		GridBagConstraints gridBagConstraints1 = new GridBagConstraints();
		gridBagConstraints1.gridx = 0;
		gridBagConstraints1.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints1.anchor = GridBagConstraints.WEST;
		gridBagConstraints1.gridy = 3;
		fontLabel = new JLabel();
		fontLabel.setText("Font");
		GridBagConstraints gridBagConstraints6 = new GridBagConstraints();
		gridBagConstraints6.anchor = GridBagConstraints.WEST;
		gridBagConstraints6.gridx = 0;
		gridBagConstraints6.gridy = 2;
		gridBagConstraints6.fill = GridBagConstraints.NONE;
		gridBagConstraints6.insets = new Insets(0, 0, 5, 0);
		encodingLabel = new JLabel();
		encodingLabel.setText("Encoding");
		GridBagConstraints gridBagConstraints5 = new GridBagConstraints();
		gridBagConstraints5.anchor = GridBagConstraints.WEST;
		gridBagConstraints5.gridx = 1;
		gridBagConstraints5.gridy = 0;
		gridBagConstraints5.ipadx = 0;
		gridBagConstraints5.fill = GridBagConstraints.HORIZONTAL;
		gridBagConstraints5.insets = new Insets(0, 0, 5, 5);
		GridBagConstraints gridBagConstraints4 = new GridBagConstraints();
		gridBagConstraints4.anchor = GridBagConstraints.WEST;
		gridBagConstraints4.gridy = 0;
		gridBagConstraints4.ipadx = 0;
		gridBagConstraints4.insets = new Insets(0, 0, 5, 0);
		gridBagConstraints4.gridx = 0;
		this.setLayout(new GridBagLayout());
		this.setSize(new Dimension(303, 270));
		this.add(getWrapLineCheckBox(), gridBagConstraints4);
		this.add(getWrapWordCheckBox(), gridBagConstraints5);
		this.add(encodingLabel, gridBagConstraints6);
		this.add(fontLabel, gridBagConstraints1);
		this.add(getFontButton(), gridBagConstraints2);
		this.add(backgroundLabel, gridBagConstraints11);
		this.add(getBackgroundButton(), gridBagConstraints21);
		this.add(foregroundLabel, gridBagConstraints3);
		this.add(getForegroundButton(), gridBagConstraints41);
		this.add(colorsSeparator, gridBagConstraints61);
		this.add(tabSizeLabel, gridBagConstraints12);
		this.add(getTabSizeTextField(), gridBagConstraints22);
		this.add(getGluePane(), gridBagConstraints);
		this.add(selectionLabel, gridBagConstraints13);
		this.add(getSelectionColorButton(), gridBagConstraints23);
		this.add(getCharsetComboBox(), gridBagConstraints14);
	}

	private JCheckBox getWrapLineCheckBox() {
		if (wrapLineCheckBox == null) {
			wrapLineCheckBox = new JCheckBox();
			wrapLineCheckBox.setText("Wrap Line");
			wrapLineCheckBox.addActionListener(this);
			wrapLineCheckBox.addActionListener(new ActionListener() {
				public void actionPerformed(ActionEvent e) {
					boolean selected = getWrapLineCheckBox().isSelected();
					getWrapWordCheckBox().setEnabled(selected);
				}
			});
		}
		return wrapLineCheckBox;
	}

	private JCheckBox getWrapWordCheckBox() {
		if (wrapWordCheckBox == null) {
			wrapWordCheckBox = new JCheckBox();
			wrapWordCheckBox.setEnabled(false);
			wrapWordCheckBox.setText("Wrap Word");
			wrapWordCheckBox.addActionListener(this);
		}
		return wrapWordCheckBox;
	}

	private FontSelectorButton getFontButton() {
		if (fontButton == null) {
			fontButton = new FontSelectorButton("Font");
			fontButton.addFontChangeListener(this);
		}
		return fontButton;
	}

	private ColorSelectorButton getBackgroundButton() {
		if (backgroundButton == null) {
			backgroundButton = new ColorSelectorButton("Background Color");
			backgroundButton.addColorChangeListener(this);
		}
		return backgroundButton;
	}

	private ColorSelectorButton getForegroundButton() {
		if (foregroundButton == null) {
			foregroundButton = new ColorSelectorButton("Text Color");
			foregroundButton.addColorChangeListener(this);
		}
		return foregroundButton;
	}

	private JPanel getGluePane() {
		if (gluePane == null) {
			gluePane = new JPanel();
		}
		return gluePane;
	}

	private JTextField getTabSizeTextField() {
		if (tabSizeTextField == null) {
			tabSizeTextField = new JTextField();
			tabSizeTextField.addActionListener(this);
			tabSizeTextField.getDocument().addDocumentListener(this);
		}
		return tabSizeTextField;
	}

	private ColorSelectorButton getSelectionColorButton() {
		if (selectionColorButton == null) {
			selectionColorButton = new ColorSelectorButton("Selection Color");
			selectionColorButton.addActionListener(this);
		}
		return selectionColorButton;
	}

	private CharsetSelectorComboBox getCharsetComboBox() {
		if (charsetComboBox == null) {
			charsetComboBox = new CharsetSelectorComboBox(CharsetUtils.getCharsets(Locale.getDefault()));
			charsetComboBox.addCharsetChangeListener(this);
		}
		return charsetComboBox;
	}
}
